package gui;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import processing.core.PApplet;

public class Axes extends Widget {
	
	private float xMin=0, xMax=1, yMin=0, yMax=1; // data ranges
	private int col = pa.color(0);
	private float fontSize = 12;
	
	private String title = null;
	private String xLabel = null;
	private String yLabel = null;
	private HashMap<Float, String> xTicks;
	private HashMap<Float, String> yTicks;
	private boolean xAxisHold = false;
	private boolean yAxisHold = false;
	  
	private boolean gridOn = false;
	private boolean axesOn = true;
	private boolean labelsOn = true;
	private int gridColor = pa.color(255);
	  	  
	public Axes(PApplet parentApplet, float[] position, 
			 double[] xData, double[] yData, Object... args) {
		// xData and yData are assumed to be sorted
		super(parentApplet, position, args);

		updateAxes(xData, yData);
	}
	
	public void title(String title) {
		this.title = title;
	}

	public void xLabel(String xLabel) {
		this.xLabel = xLabel;
	}

	public void yLabel(String yLabel) {
		this.yLabel = yLabel;
	}
	
	protected void updateAxes(double[] xData, double[] yData) {
		findXRange(xData);
		findYRange(yData);
		xTicks = findTicks(xData);
		yTicks = findTicks(yData);
	}
		  	  	  
	public void setAppearance(int col, float fontSize) {
	    this.col = col;
	    this.fontSize = fontSize;
	  }

	public void findXRange(double[] xData) {
		xMin = (float)xData[0];
		xMax = (float)xData[0];
		for (int i=0; i < xData.length-1; i++) {
			if (xMin > xData[i]) {
				xMin = (float)xData[i];
			};
			if (xMax < xData[i]) {
				xMax = (float)xData[i];
			};
		}
	}
	  
	public void findYRange(double[] yData) {
		yMin = (float)yData[0];
		yMax = (float)yData[0];
		for (int i=0; i < yData.length-1; i++) {
			if (yMin > yData[i]) {
				yMin = (float)yData[i];
			};
			if (yMax < yData[i]) {
				yMax = (float)yData[i];
			};
		}
	}
	
	public void setXRange(float xMin, float xMax) {
	    this.xMin = xMin;
	    this.xMax = xMax;
	}
	  
	public void setYRange(float yMin, float yMax) {
	    this.yMin = yMin;
	    this.yMax = yMax;
	}
		  
	public float left() {return x0;}
	public float right() {return x0 + width;}
	public float top() {return y0;}
	public float bottom() {return y0 + height;}
	  
	public float xmin() {return xMin;}
	public float xmax() {return xMax;}
	public float ymin() {return yMin;}
	public float ymax() {return yMax;}
	  
	public float scr2x(float s) {return pa.map(s, left(), right(), xmin(), xmax());}
	public float scr2y(float s) {return pa.map(s, bottom(), top(), ymin(), ymax());}
	public float x2scr(float x) {return pa.map(x, xmin(), xmax(), left(), right());}
	public float y2scr(float y) {return pa.map(y, ymin(), ymax(), bottom(), top());}
	  
	public float mouseXd() {return scr2x(pa.mouseX);}
	public float mouseYd() {return scr2y(pa.mouseY);}

	private HashMap<Float, String> findTicks(double[] axisData) {
		HashMap ticks = new HashMap();
		double min = axisData[0];
		double max = axisData[0];
		for (int i=0; i < axisData.length-1; i++) {
			if (min > axisData[i]) {
				min = axisData[i];
			};
			if (max < axisData[i]) {
				max = axisData[i];
			};
		}
  		DecimalFormat labelFormatter = new DecimalFormat("0.#E0");
		
		for (int i=0; i < 6; i++) {
			String label = labelFormatter.format((max-min)/5. * (double)i);
			ticks.put(new Float((max-min)/5. * (double)i + min ), label);
		}
		
		return ticks;
	}
	
	private void drawXTicks() {
	    Iterator tickIterator = xTicks.entrySet().iterator();
	    
	    pa.stroke(1);
	    pa.fill(0);
	    pa.textAlign(pa.CENTER, pa.TOP);
    
	    while (tickIterator.hasNext()) {
		    Map.Entry tick = (Map.Entry)tickIterator.next();
		    float position = ((Float) tick.getKey()).floatValue();
		    String label = (String) tick.getValue();
		    
		    pa.line(x2scr(position), bottom(), x2scr(position), (float) (bottom() - 2.));
		    
		    pa.text(label, x2scr(position), (float)(bottom()+5.));
		    
	    }
	}

	private void drawYTicks() {	    
	    pa.stroke(1);
	    pa.fill(0);
	    pa.textAlign(pa.RIGHT, pa.CENTER);
    
	    for (Map.Entry tick : yTicks.entrySet()) {
		    float position = ((Float) tick.getKey()).floatValue();
		    String label = (String) tick.getValue();
		    
		    pa.line(left(), y2scr(position), (float) (left() + 2.), y2scr(position));
		    pa.text(label, (float)(left()-5.), y2scr(position));
		    
	    }
	}
	
	private void drawAxes() {drawAxes(col,1);}
	private void drawAxes(int col, float wt) {
		pa.stroke(col);
		pa.strokeWeight(wt);
		pa.noFill();
		pa.rect(x0-1, y0-1, width+1, height+1);
		drawXTicks();
		drawYTicks();
	}

	private void drawLabels() {
		if (title != null) {
			pa.textAlign(pa.CENTER);
			pa.text(title, (x0 + width/((float)2.)), y0 - 5 );
		}
		if (xLabel != null) {
			pa.textAlign(pa.CENTER);
			pa.text(xLabel, (x0 + width/((float)2.)), y0 + height + 30 );
		}
		if (yLabel != null) {
			pa.pushMatrix();
			pa.translate(x0, y0+height);
			pa.rotate(pa.PI);
			pa.rotate(pa.HALF_PI);
			pa.textAlign(pa.CENTER);
			pa.text(yLabel, (height/((float)2.)), -35);
			pa.popMatrix();
		}
	}
	
	public void draw() {
		drawAxes();
		drawLabels();
	}
 	
}
